package com.qd.panda.service.park;

import cn.hutool.core.math.Money;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.core.weixinmanager.domain.QrDTO;
import com.cdqidi.core.weixinmanager.service.wx.WxaApiService;
import com.cdqidi.core.weixinmanager.util.CallWxUtil;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.excel.util.ExportPage;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.RedisTemplateUtil;
import com.cdqidi.util.SpringContextHolder;
import com.cdqidi.util.ValidatorUtil;
import com.cdqidi.valid.group.DefaultGroup;
import com.cdqidi.valid.group.UpdateGroup;
import com.fasterxml.jackson.databind.JsonNode;
import com.jfinal.springboot.weixin.annotation.ApiType;
import com.qd.common.panda.config.PandaParkConfigDTO;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.carpark.*;
import com.qd.common.panda.domain.search.CarParkSearch;
import com.qd.common.sys.domain.entity.org.OrgDTO;
import com.qd.common.sys.domain.entity.upload.FileUploadDTO;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.common.sys.enums.BaseTableEnum;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.panda.model.*;
import com.qd.panda.model.CarParkFee;
import com.qd.panda.service.rule.BillRuleSetService;
import com.qd.system.service.dict.MbUtil;
import com.qd.system.service.org.OrgHoldService;
import com.qd.system.service.org.OrgService;
import com.qd.system.util.FileConfirmUtil;
import com.qd.upload.constant.FileConfirmDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author sjk
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ParkHolderService {
    private final CarParkService carParkservice;
    private final CarParkFeeService carParkFeeService;
    private final CarParkTimeService carParkTimeService;
    private final CarParkImgService carParkImgService;
    private final CarParkLocationService carParkLocationService;
    private final CarParkAppointmentSetService appointmentSetService;
    private final PandaParkConfigDTO pandaParkConfig;
    private final CarParkFeeLogService carParkFeeLogService;
    private final CarParkChargeService carParkChargeService;
    private final CarParkChargeFeeService carParkChargeFeeService;
    private final CarParkRevenueService carParkRevenueService;

    @Resource
    private WxaApiService wxaApiService;
    private final ValidatorUtil validatorUtil;

    private final RedisTemplateUtil<Objects> redisTemplateUtil;
    private final BillRuleSetService billRuleSetService;

    private final OrgService orgService;
    private final OrgHoldService orgHoldService;


    @Transactional(rollbackFor = Exception.class)
    public CarParkDTO save(CarParkDTO carParkDTO, boolean isLoadCache) {
        String pId;
        if (StringUtils.hasLength(carParkDTO.getPId())) {
            pId = carParkDTO.getPId();
        } else {
            pId = IdWorker.getIdStr();
        }
        LoginUser loginUser = SecurityUtils.getLoginUser(false);

        carParkDTO.setPId(pId);
        carParkDTO.setAddTime(LocalDateTime.now());

        if (null != loginUser) {
            if (!StringUtils.hasLength(carParkDTO.getOperator())) {
                carParkDTO.setOperator(loginUser.getUserId());
            }
            if (!StringUtils.hasLength(carParkDTO.getOrgId())) {
                carParkDTO.setOrgId(loginUser.getCurrentOrgId());
            }
        }

        buildQrCode(carParkDTO);

        {
            if (carParkDTO.getParkType().equals(PandaConstant.PARK_TYPE_CAR_PARK)) {
                //如果是停车场
                CarParkFeeDTO fee = carParkDTO.getFee();
                CarParkTimeDTO time = carParkDTO.getTime();
                List<CarParkRevenueDTO> revenueList = carParkDTO.getRevenueList();
                if (carParkDTO.getParkSpaceType().equals(PandaConstant.PARK_SPACE_TYPE3) || carParkDTO.getParkSpaceType().equals(PandaConstant.PARK_SPACE_TYPE4)) {
                    if (null == carParkDTO.getShareRatio()) {
                        throw new ApiException("分成比例不能为空");
                    }
                    if (!StringUtils.hasLength(carParkDTO.getGateBrand())) {
                        throw new ApiException("道闸品牌不能为空");
                    }
                    if (null == revenueList || revenueList.isEmpty()) {
                        throw new ApiException("收益设置不能为空");
                    }
                    revenueList.forEach(re -> {
                        re.setPId(pId);
                        if (null == re.getTotalRevenue() || re.getTotalRevenue().doubleValue() < 1) {
                            BigDecimal amount = new Money(re.getDayRevenue()).multiply(re.getDays()).getAmount();
                            re.setTotalRevenue(amount);
                        }
                        if (MbUtil.isNotExists(re.getLeaseType(), BaseTableEnum.LEASE_TYPE)) {
                            throw new ApiException("租赁类型值错误");
                        }
                        validatorUtil.checkValid(re, DefaultGroup.class);
                    });
                    List<CarParkRevenue> carParkRevenues = carParkRevenueService.dtoToModelList(revenueList);
                    carParkRevenueService.saveBatch(carParkRevenues);
                    revenueList.clear();
                    carParkRevenues.clear();
                } else {
                    if (null == fee) {
                        throw new ApiException("停车场费用不能为空");
                    }
                    if (null == time) {
                        throw new ApiException("停车时段不能为空");
                    }
                }
                if(null !=fee){
                    fee.setPId(pId);
                    fee.setSid(IdWorker.getIdStr());
                    validatorUtil.checkValid(fee, DefaultGroup.class);
                    checkFee(carParkDTO);
                    carParkFeeService.save(fee);
                    saveCarParkFeeLog(fee, carParkDTO);
                    fee.freeData();
                }
                if(null !=fee){
                    time.setPId(pId);
                    validatorUtil.checkValid(time, DefaultGroup.class);
                    carParkTimeService.save(time);
                    time.freeData();
                }
            }
        }
        {
            if (carParkDTO.getParkType().equals(PandaConstant.PARK_TYPE_CHARGING_STATION)) {
                //充电站
                final CarParkChargeDTO charge = carParkDTO.getCharge();
                if (null == charge) {
                    throw new ApiException("充电信息不能为空");
                }
                charge.setPId(pId);
                validatorUtil.checkValid(charge, DefaultGroup.class);
                carParkChargeService.save(charge);

                CarParkChargeFeeDTO carParkChargeFee = charge.getCarParkChargeFee();
                if(null == carParkChargeFee){
                    throw new ApiException("充电免费停车设置不能为空");
                }
                carParkChargeFee.setPId(pId);
                validatorUtil.checkValid(carParkChargeFee, DefaultGroup.class);
                carParkChargeFeeService.save(carParkChargeFee);

                charge.freeData();
                carParkChargeFee.freeData();
            }
        }

        {
            List<CarParkImgDTO> files = carParkDTO.getImgList();
            if (null != files && !files.isEmpty()) {
                files.forEach(carParkImgDTO -> {
                    carParkImgDTO.setPId(pId);
                    validatorUtil.checkValid(carParkImgDTO, DefaultGroup.class);
                });
                carParkImgService.saveBatch(files.stream().map(carParkImgDTO -> this.buildCarParkImg(pId, carParkImgDTO)).collect(Collectors.toList()));
            }
        }
        {
            final CarParkLocationDTO location = carParkDTO.getLocation();
            if (null == location) {
                throw new ApiException("位置信息不能为空");
            }
            location.setPId(pId);
            validatorUtil.checkValid(location, DefaultGroup.class);
            carParkLocationService.save(location);
            location.freeData();
        }

        {
            CarParkAppointmentSetDTO appointmentSet = carParkDTO.getAppointmentSet();
            if (null != appointmentSet) {
                appointmentSet.setPId(pId);
                validatorUtil.checkValid(appointmentSet, DefaultGroup.class);
                appointmentSetService.save(appointmentSet);
                appointmentSet.freeData();
            }
        }

        carParkservice.save(carParkDTO);
        if (carParkDTO.getCarParkType().equals(PandaConstant.CAR_PARK_TYPE_0)) {
            syncToSysOrg(carParkDTO);
        }

        carParkDTO.freeData();

        if (isLoadCache) {
            CarParkDTO carPark = carParkservice.getByIdDto(pId);
            if(null == carPark){
                log.info("CarParkDTO为空,pId: {}",pId);
            }else{
                carParkservice.buildToRedis(carPark, null);
            }
            return carPark;
        }

        return null;
    }

    /**
     * 更新停车场信息
     *
     * @param carParkDTO 停车场信息
     * @return 停车场信息
     */
    @Transactional(rollbackFor = Exception.class)
    public CarParkDTO update(CarParkDTO carParkDTO) {
        String pId = carParkDTO.getPId();
        if (!StringUtils.hasLength(pId)) {
            throw new ApiException("停车场ID不能为空");
        }
        carParkDTO.setUpdateTime(LocalDateTime.now());
        final LoginUser loginUser = SecurityUtils.getLoginUser(false);
        if (null != loginUser) {
            if (!StringUtils.hasLength(carParkDTO.getOperator())) {
                carParkDTO.setOperator(loginUser.getUserId());
            }
            if (!StringUtils.hasLength(carParkDTO.getOrgId())) {
                carParkDTO.setOrgId(loginUser.getCurrentOrgId());
            }
        }
        {
            Optional.ofNullable(carParkDTO.getLocation()).ifPresent(carParkLocationDTO -> {
                carParkLocationDTO.setPId(pId);
                if (Boolean.TRUE.equals(carParkLocationService.isExistsById(pId))) {
                    validatorUtil.checkValid(carParkLocationDTO, DefaultGroup.class, UpdateGroup.class);
                    carParkLocationService.update(carParkLocationDTO);
                } else {
                    validatorUtil.checkValid(carParkLocationDTO, DefaultGroup.class);
                    carParkLocationService.save(carParkLocationDTO);
                }
            });
        }
        {
            Optional.ofNullable(carParkDTO.getImgList()).ifPresent(files -> {
                List<CarParkImgDTO> newList = files.stream().filter(image -> StringUtils.hasLength(image.getFileId())).collect(Collectors.toList());
                newList.forEach(carParkImgDTO -> {
                    carParkImgDTO.setPId(pId);
                    if (!StringUtils.hasLength(carParkImgDTO.getAttachmentType())) {
                        throw new ApiException("文件类型不能为空");
                    }
                    Optional.of(buildCarParkImg(pId, carParkImgDTO)).ifPresent(carParkImg -> {
                        carParkImgDTO.setPicName(carParkImg.getPicName());
                        carParkImgDTO.setPicPath(carParkImg.getPicPath());
                    });
                    if (StringUtils.hasLength(carParkImgDTO.getId())) {
                        validatorUtil.checkValid(carParkImgDTO, DefaultGroup.class, UpdateGroup.class);
                        carParkImgService.update(carParkImgDTO);
                    } else {
                        validatorUtil.checkValid(carParkImgDTO, DefaultGroup.class);
                        carParkImgService.save(carParkImgDTO);
                    }
                });
            });
        }

        {
            Optional.ofNullable(carParkDTO.getAppointmentSet()).ifPresent(appointmentSet -> {
                appointmentSet.setPId(pId);
                if (Boolean.TRUE.equals(appointmentSetService.isExistsById(pId))) {
                    validatorUtil.checkValid(appointmentSet, DefaultGroup.class);
                    appointmentSetService.update(appointmentSet);
                } else {
                    validatorUtil.checkValid(appointmentSet, DefaultGroup.class);
                    appointmentSetService.save(appointmentSet);
                }
            });
        }
        {
            Optional.ofNullable(carParkDTO.getCharge()).ifPresent(carParkChargeDTO -> {
                carParkChargeDTO.setPId(pId);
                validatorUtil.checkValid(carParkChargeDTO, DefaultGroup.class);
                if (Boolean.TRUE.equals(carParkChargeService.isExistsById(pId))) {
                    carParkChargeService.update(carParkChargeDTO);
                } else {
                    carParkChargeService.save(carParkChargeDTO);
                }
                CarParkChargeFeeDTO carParkChargeFee = carParkChargeDTO.getCarParkChargeFee();
                if(null!=carParkChargeFee){
                    carParkChargeFee.setPId(pId);
                    if (StringUtils.hasLength(carParkChargeFee.getSid())) {
                        validatorUtil.checkValid(carParkChargeFee, DefaultGroup.class,UpdateGroup.class);
                        carParkChargeFeeService.update(carParkChargeFee);
                    }else{
                        validatorUtil.checkValid(carParkChargeFee, DefaultGroup.class);
                        carParkChargeFeeService.save(carParkChargeFee);
                    }
                    carParkChargeFee.freeData();
                }
            });
        }
        {
            Optional.ofNullable(carParkDTO.getFee()).ifPresent(carParkFeeDTO -> {
                carParkFeeDTO.setPId(pId);
                final CarParkFee carParkFee = carParkFeeService.getUniqueByPId(carParkFeeDTO.getPId());
                checkFee(carParkDTO);
                if (null == carParkFee) {
                    carParkFeeDTO.setSid(IdWorker.getIdStr());
                    validatorUtil.checkValid(carParkFeeDTO, DefaultGroup.class);
                    carParkFeeService.save(carParkFeeDTO);
                } else {
                    carParkFeeDTO.setSid(carParkFee.getSid());
                    validatorUtil.checkValid(carParkFeeDTO, DefaultGroup.class, UpdateGroup.class);
                    carParkFeeService.update(carParkFeeDTO);
                }
                saveCarParkFeeLog(carParkFeeDTO, carParkservice.getByIdDto(carParkDTO.getPId()));
            });
        }

        {
            Optional.ofNullable(carParkDTO.getTime()).ifPresent(carParkTimeDTO -> {
                carParkTimeDTO.setPId(pId);
                final CarParkTime carParkTime = carParkTimeService.getUniqueByPId(carParkTimeDTO.getPId());
                if (null == carParkTime) {
                    validatorUtil.checkValid(carParkTimeDTO, DefaultGroup.class);
                    carParkTimeService.save(carParkTimeDTO);
                } else {
                    carParkTimeDTO.setTId(carParkTime.getTId());
                    validatorUtil.checkValid(carParkTimeDTO, DefaultGroup.class, UpdateGroup.class);
                    carParkTimeService.update(carParkTimeDTO);
                }
            });
        }
        {
            Optional.ofNullable(carParkDTO.getRevenueList()).ifPresent(l -> {
                List<CarParkRevenue> addList = new ArrayList<>(carParkDTO.getRevenueList().size());
                List<CarParkRevenue> updateList = new ArrayList<>(carParkDTO.getRevenueList().size());
                for (CarParkRevenueDTO carParkRevenueDTO : l) {
                    carParkRevenueDTO.setPId(pId);
                    if (null == carParkRevenueDTO.getTotalRevenue() || carParkRevenueDTO.getTotalRevenue().doubleValue() < 1) {
                        BigDecimal amount = new Money(carParkRevenueDTO.getDayRevenue()).multiply(carParkRevenueDTO.getDays()).getAmount();
                        carParkRevenueDTO.setTotalRevenue(amount);
                    }
                    if (MbUtil.isNotExists(carParkRevenueDTO.getLeaseType(), BaseTableEnum.LEASE_TYPE)) {
                        throw new ApiException("租赁类型值错误");
                    }
                    if (StringUtils.hasLength(carParkRevenueDTO.getRid())) {
                        if (carParkRevenueService.isExists(carParkRevenueDTO.getRid())) {
                            validatorUtil.checkValid(carParkRevenueDTO, DefaultGroup.class, UpdateGroup.class);
                            updateList.add(carParkRevenueService.dtoToModel(carParkRevenueDTO));
                            continue;
                        }
                    }
                    validatorUtil.checkValid(carParkRevenueDTO, DefaultGroup.class);
                    addList.add(carParkRevenueService.dtoToModel(carParkRevenueDTO));
                }
                if (!addList.isEmpty()) {
                    carParkRevenueService.saveBatch(addList);
                    addList.clear();
                }
                if (!updateList.isEmpty()) {
                    carParkRevenueService.updateBatchIds(updateList);
                    updateList.clear();
                }
            });
        }

        carParkservice.update(carParkDTO);
        syncToSysOrg(carParkDTO);
        carParkDTO.freeData();

        CarParkDTO carPark = carParkservice.getByIdDto(pId);
        carParkservice.buildToRedis(carPark);
        return carPark;
    }

    /**
     * 删除单个停车场信息
     *
     * @param pId 停车场ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeById(String pId) {
        remove(pId);
        deleteSysOrg(pId);
    }

    /**
     * 批量删除停车场信息
     *
     * @param ids 停车场ID集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeBatchIds(List<String> ids) {
        ids.forEach(id -> {
            remove(id);
            deleteSysOrg(id);
        });
    }

    /**
     * 停车场状态是否为开起
     *
     * @param pId 停车场ID
     * @return 状态
     */
    public boolean carParkEnable(String pId) {
        return Optional.ofNullable(carParkservice.getCarParkInfoByRedis(pId)).map(CarParkInfoDTO::getEnable).orElse(ConstantDto.SF0).equals(ConstantDto.SF1);
    }

    /**
     * 保存停车场费用设置记录
     *
     * @param dto     停车场费用设置
     * @param carPark 停车场信息
     */
    private void saveCarParkFeeLog(CarParkFeeDTO dto, CarParkDTO carPark) {
        final LoginUser loginUser = SecurityUtils.getLoginUser(false);
        if (!StringUtils.hasLength(carPark.getPId())) {
            return;
        }
        if (!StringUtils.hasLength(carPark.getName())) {
            carPark = carParkservice.getByIdDto(carPark.getPId());
        }
        if (null == carPark) {
            return;
        }
        if (carPark.getThirdPartyBill().equals(ConstantDto.SF1)) {
            //第三方计费，无需要存费用设置信息
            return;
        }
        CarParkFeeLog carParkFeeLog = new CarParkFeeLog();
        carParkFeeLog.setAddTime(carPark.getAddTime());
        carParkFeeLog.setUpdateTime(carPark.getUpdateTime());
        if (null == loginUser) {
            if (StringUtils.hasLength(carPark.getOrgId())) {
                carParkFeeLog.setOrgId(carPark.getOrgId());
            }
            if (StringUtils.hasLength(carPark.getOperator())) {
                carParkFeeLog.setOperator(carPark.getOperator());
            }
        } else {
            carParkFeeLog.setOperator(loginUser.getUserId());
            carParkFeeLog.setOrgId(loginUser.getCurrentOrgId());
        }
        carParkFeeLog.setBillRule(dto.getBillRule());
        carParkFeeLog.setNote(dto.getNote());
        Optional.ofNullable(dto.getRule()).ifPresent(jsonNode -> carParkFeeLog.setRule(jsonNode.toString()));
        carParkFeeLog.setSid(dto.getSid());
        carParkFeeLog.setParkId(dto.getPId());
        carParkFeeLog.setParkName(carPark.getName());
        if (null != carPark.getLocation()) {
            if (StringUtils.hasLength(carPark.getLocation().getAddress())) {
                carParkFeeLog.setParkAddress(carPark.getLocation().getAddress());
            }
        }
        carParkFeeLogService.save(carParkFeeLog);
        carParkFeeLog.freeData();
    }

    public void buildQrCode(CarParkDTO carParkDTO) {
        final String activeProfile = SpringContextHolder.getActiveProfile();
        final String appId = pandaParkConfig.getDefaultMiniProgramAppId();
        if (!StringUtils.hasLength(appId)) {
            throw new ApiException("默认小程序ID不能为空，生成葵花码异常");
        }
        //生成葵花码
        carParkDTO.setCode(getCode(0));
        if (Objects.equals(carParkDTO.getCarParkType(), PandaConstant.CAR_PARK_TYPE_1)) {
            //交投不生成
            return;
        }

        if (Objects.equals(carParkDTO.getParkType(), PandaConstant.PARK_TYPE_GAS_STATION)) {
            //加油站不生成
            return;
        }
        CallWxUtil.callInterface(appId, ApiType.WXA, () -> {
            QrDTO qrDTO = new QrDTO();
            ApiResultWrapper<Object> resultWrapper;
            if (activeProfile.equals(SpringContextHolder.PROFILE_OFFICIAL)) {
                //正式环境
                qrDTO.setScene("pId=" + carParkDTO.getPId())
                        .setName(carParkDTO.getPId())
                        .setAutoColor(true)
                        .setIsHyAline(false)
                        .setPage("pages/shared/scane-park/scane-park");
                resultWrapper = wxaApiService.getUnlimited(qrDTO);
            } else {
                qrDTO.setScene("pId=" + carParkDTO.getPId())
                        .setName(carParkDTO.getPId())
                        .setAutoColor(true)
                        .setIsHyAline(false)
                        .setPath("pages/shared/scane-park/scane-park");
                resultWrapper = wxaApiService.getQrCode(qrDTO);
            }
            if (resultWrapper.isSuccess()) {
                log.info(resultWrapper.getData().toString());
                carParkDTO.setQrCode(resultWrapper.getData().toString());
            } else {
                throw new ApiException(resultWrapper.getMsg());
            }
            return null;
        });


    }

    public String getCode(int count) {
        if (count > 100) {
            return null;
        }
        String s = RandomUtil.randomString(8);
        CarPark carPark = carParkservice.getUniqueByCode(s);
        if (null != carPark) {
            count++;
            return getCode(count);
        }
        return s;
    }

    private CarParkImg buildCarParkImg(String pId, CarParkImgDTO carParkImgDTO) {
        if (!StringUtils.hasLength(carParkImgDTO.getFileId())) {
            throw new ApiException("文件ID不能为空");
        }
        if (!StringUtils.hasLength(carParkImgDTO.getAttachmentType())) {
            throw new ApiException("文件类型不能为空");
        }
        FileUploadDTO fileUploadDto = new FileUploadDTO();
        fileUploadDto.setId(carParkImgDTO.getFileId());
        fileUploadDto.setAttachmentType(carParkImgDTO.getAttachmentType());

        CarParkImg carParkImg = new CarParkImg();
        FileConfirmDTO fileConfirmDto = FileConfirmUtil.singleFileConfirm(fileUploadDto.getId(), fileUploadDto.getAttachmentType());
        if (null == fileConfirmDto) {
            throw new ApiException("文件ID不存在[" + fileUploadDto.getId() + "]");
        }
        carParkImg.setPId(pId);
        if (null != carParkImgDTO.getIdx() && carParkImgDTO.getIdx() > 0) {
            carParkImg.setIdx(carParkImgDTO.getIdx());
        }
        carParkImg.setId(fileConfirmDto.getFileId());
        carParkImg.setPicPath(fileConfirmDto.getOfficialFile());
        if (StringUtils.hasLength(carParkImgDTO.getPicName())) {
            carParkImg.setPicName(carParkImgDTO.getPicName());
        } else {
            carParkImg.setPicName(fileConfirmDto.getFileName());
        }
        return carParkImg;
    }

    private void remove(String pId) {
        carParkservice.removeById(pId);
        Optional.ofNullable(carParkFeeService.getUniqueByPId(pId)).ifPresent(carParkFee -> carParkFeeService.removeById(carParkFee.getSid()));
        if(Boolean.TRUE.equals(carParkLocationService.isExistsById(pId))){
            carParkLocationService.removeById(pId);
        }
        if(Boolean.TRUE.equals(appointmentSetService.isExistsById(pId))){
            appointmentSetService.removeById(pId);
        }
        if(carParkChargeService.isExists(pId)){
            carParkChargeService.removeById(pId);
        }
        Optional.ofNullable(carParkChargeFeeService.getUniqueByPId(pId)).ifPresent(carParkChargeFee -> carParkChargeFeeService.removeById(carParkChargeFee.getSid()));

        {
            CarParkTimeDTO carParkTimeDTO = new CarParkTimeDTO();
            carParkTimeDTO.setPId(pId);
            Optional.ofNullable(carParkTimeService.getList(carParkTimeDTO)).ifPresent(list -> list.forEach(carParkTime -> carParkTimeService.removeById(carParkTime.getTId())));
        }
        {
            CarParkImgDTO carParkImgDTO = new CarParkImgDTO();
            carParkImgDTO.setPId(pId);
            Optional.ofNullable(carParkImgService.getList(carParkImgDTO)).ifPresent(list -> list.forEach(carParkImg -> carParkImgService.removeById(carParkImg.getId())));
        }
    }

    @Transactional(readOnly = true)
    public ApiResultWrapper<Object> loadCache() {
        Optional.ofNullable(redisTemplateUtil.scan(RedisTemplateUtil.buildKey(CarParkService.PREFIX_ID_REDIS.replace("{0}", "*"),true))).ifPresent(keys -> redisTemplateUtil.getStringRedisTemplate().delete(keys));
        Optional.ofNullable(redisTemplateUtil.scan(RedisTemplateUtil.buildKey(CarParkLocationService.GEO_ID.replace("{0}", "*"),true))).ifPresent(keys -> redisTemplateUtil.getStringRedisTemplate().delete(keys));
        final ExportPage<CarPark, CarPark> exportPage = new ExportPage<>();
        final List<CarPark> list = exportPage.getAllForPage(page -> carParkservice.getBaseMapper().selectPage(page, new QueryWrapper<>()).getRecords());
        long size = (null == list || list.isEmpty()) ? 0 : list.size();
        if (size > 0) {
            list.forEach(carPar -> {
                CarParkDTO carParkDTO = carParkservice.modelToDto(carPar);
                carParkservice.buildToRedis(carParkDTO);
                if(null != carParkDTO.getLocation()){
                    carParkLocationService.buildRedis(carParkDTO.getPId(), carParkDTO.getLocation().getLat(), carParkDTO.getLocation().getLng());
                }
                carParkDTO.freeData();
            });
            list.clear();
        }
        log.info("刷新缓存，条数:{}", size);
        return ApiResult.success(size);
    }

    private void checkFee(CarParkDTO carParkDTO) {
        String thirdPartyBill = carParkDTO.getThirdPartyBill();
        if (!StringUtils.hasLength(thirdPartyBill)) {
            thirdPartyBill = Optional.ofNullable(carParkservice.getById(carParkDTO.getPId())).map(CarPark::getThirdPartyBill).orElse(null);
        }
        //不是第三方计费，就是我们自己计费，那么规则必填
        if (StringUtils.hasLength(thirdPartyBill) && thirdPartyBill.equals(ConstantDto.SF0)) {
            if (!StringUtils.hasLength(carParkDTO.getFee().getBillRule())) {
                throw new ApiException("请选择停车场计费规则");
            }
            JsonNode rule = carParkDTO.getFee().getRule();
            if (null == rule) {
                throw new ApiException("请填写规则");
            }
            billRuleSetService.getRuleDTO(carParkDTO.getFee().getBillRule(), rule);

        }
    }

    /**
     * 同步到组织机构
     */
    public void syncToSysOrg(CarParkDTO carParkDTO) {
        String parentOrgId = carParkDTO.getOrgId();
        String orgId = carParkDTO.getPId();
        String name = carParkDTO.getName();
        if (!StringUtils.hasLength(parentOrgId)) {
            throw new ApiException("组织机构ID不能为空");
        }
        if (!StringUtils.hasLength(orgId)) {
            throw new ApiException("停车场ID不能为空");
        }
        if (!StringUtils.hasLength(name)) {
            throw new ApiException("停车场名字不能为空");
        }
        if (Boolean.FALSE.equals(orgService.isExistsById(parentOrgId))) {
            throw new ApiException("组织机构ID不存在");
        }
        //交投的不同步
        if (carParkDTO.getCarParkType().equals(PandaConstant.CAR_PARK_TYPE_1)) {
            return;
        }
        OrgDTO orgDto = orgService.getByIdDto(orgId);
        if (null == orgDto) {
            orgDto = new OrgDTO();
            orgDto.setOrgId(orgId);
            orgDto.setParentId(parentOrgId);
            orgDto.setOrgName(name);
            orgDto.setAddTime(LocalDateTime.now());
            orgDto.setOrgStatus(0);
            orgService.saveOrg(orgDto);
        } else {
            if (!orgDto.getOrgName().equals(name) || !orgDto.getParentId().equals(parentOrgId)) {
                orgDto.setParentId(parentOrgId);
                orgDto.setOrgName(name);
                orgDto.setUpdateTime(LocalDateTime.now());
                orgService.updateOrg(orgDto);
            }
        }
        orgDto.freeData();
    }

    /**
     * 删除系统组织机构中的停车场数据
     *
     * @param orgId 停车场ID
     */
    public void deleteSysOrg(String orgId) {
        if (Boolean.TRUE.equals(orgService.isExistsById(orgId))) {
            orgHoldService.deleteByOrgId(orgId);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncBathSysOrg() {
        final ExportPage<CarParkSearch, CarParkDTO> exportPage = new ExportPage<>();
        final List<CarParkDTO> list = exportPage.getAllForPage(page -> carParkservice.page(page, new CarParkSearch().setCarParkType(PandaConstant.CAR_PARK_TYPE_0)).getRecords());
        if (!list.isEmpty()) {
            list.forEach(this::syncToSysOrg);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public String createQrCode(String parkId) {
        CarParkDTO carParkDTO = Optional.ofNullable(carParkservice.getByIdDto(parkId)).orElseThrow(() -> new ApiException("停车场不存在"));
        buildQrCode(carParkDTO);
        String qrCodePath = FileConfirmUtil.getFilePath(carParkDTO.getQrCode(), carParkDTO.getPId() + ".jpg");
        carParkservice.update(carParkDTO);
        carParkservice.buildToRedis(carParkDTO);
        carParkDTO.freeData();
        return qrCodePath;
    }
}
